-module(client).
-import(werkzeug, [get_config_value/2, logging/2, timeMilliSecond/0, to_String/1]).
-compile(export_all).

%%%%%%%%%%%%%%%%%%%%%%
%% start
% Start und laden der Configs
%%
start(Hostname) ->
  {ok, ConfigListe} = file:consult("client.cfg"),
  {ok, Clients} = get_config_value(clients, ConfigListe),
  createprocess(Hostname, Clients).


%%%%%%%%%%%%%%%%%%%%%%
%% createprocess
% Erzeugt alle Client Prozesse
%%
createprocess(Hostname, Count) when Count > 0 ->
  {ok, Adress} = inet:gethostname(),
  ClientName = list_to_atom((lists:concat(["client", Count, "@", Adress]))),
  ClientPid = spawn(fun() -> startprog(Hostname, Count) end),
  register(ClientName, ClientPid),
  net_adm:ping(Hostname),
  timer:sleep(newtime(500)),
  createprocess(Hostname, Count - 1);
createprocess(_, _) -> "Alle Clients erzeugt".

%%%%%%%%%%%%%%%%%%%%%%
%% startprog
% Bereitet den Client vor.(Verbindung zum Server)
%%
startprog(Hostname, ClientNumber) ->
  SenderCount = 5,
  {ok, ConfigListe} = file:consult("client.cfg"),
  {ok, Sendeintervall} = get_config_value(sendeintervall, ConfigListe),
  {ok, Servername} = get_config_value(servername, ConfigListe),
  {ok, Lifetime} = werkzeug:get_config_value(lifetime, ConfigListe),
  timer:exit_after(Lifetime * 1000, self(), "Ende Lebenszeit erreicht!"),
  Pid = {Servername, Hostname},
  log_message(ClientNumber, lists:concat([to_String(ClientNumber), "-", node(), "-",to_String(self()), "-C-4-05 Start: ", timeMilliSecond(), "|."])),
  Time = (Sendeintervall * 1000),
  getmsgid(Pid, ClientNumber, Time, SenderCount, []).


%%%%%%%%%%%%%%%%%%%%%%
%% getmsgid(Redakteur)
% Holt sich 5mal eine NR und schickt eine Nachricht an den Server.
% Beim 6ten mal holt sich der Redaktur nur eine Nr und wird dann zum Leser
%%
getmsgid(Pid, ClientNumber, Sendeintervall, Times, OwnMessages) when Times > 0 ->
  Pid ! {getmsgid, self()},
  receive
    {nid, Number} ->
      dropmessage(Pid, Number, ClientNumber),
      Time = Sendeintervall,
      timer:sleep(Time),
      getmsgid(Pid, ClientNumber, Sendeintervall, Times - 1, lists:append(OwnMessages, [Number]))
  end;

getmsgid(Pid, ClientNumber, Sendeintervall, _, OwnMessages) ->
  Pid ! {getmsgid, self()},
  receive
    {nid, Number} ->
      log_message(ClientNumber, lists:concat([ClientNumber, "-", to_String(node()), "-", to_String(self()), "-C-4-05: ", Number, "te_Nachricht um ", timeMilliSecond(), "| vergessen zu senden ******\n"])),
      getmessages(Pid, ClientNumber, Sendeintervall, OwnMessages)
  end.


%%%%%%%%%%%%%%%%%%%%%%
%% dropmessage(Redakteur)
% Sendet Nachricht an Server
%%
dropmessage(Pid, Number, ClientNumber) ->
  Nachricht = lists:concat([ClientNumber, "-", to_String(node()), "-", to_String(self()), "-C-4-05: ", Number, "te_Nachricht. C Out: ", timeMilliSecond(), "|"]),
  Pid ! {dropmessage, {Nachricht, Number}},
  log_message(ClientNumber, lists:concat([Nachricht, "gesendet\n"]))
.

%%%%%%%%%%%%%%%%%%%%%%
%% getmessages (Leser)
% Holt sich alle Nachrichten vom Server die der Leser noch nicht hatte.
% Eigene Nachrichten werden ****** angehängt.
% Intervall wird auch neu gesetzt
%%
getmessages(Pid, ClientNumber, Sendeintervall, OwnMessages) ->
  Pid ! {getmessages, self()},
  receive
    {reply, Number, Nachricht, Terminated} ->
      F = fun(X) -> X =:= Number end,
      State = lists:any(F, OwnMessages),
      if State == true ->
        Apend = "*******";
      true ->
        Apend = ""
      end,
      log_message(ClientNumber, [Nachricht, ".", Apend, "; C In: ", timeMilliSecond(), "|\n"]),
      if Terminated == false ->
         getmessages(Pid, ClientNumber, Sendeintervall, OwnMessages);
      true ->
         Log2 = "..getmessages..Done...\n",
         log_message(ClientNumber, Log2),
         Time = newtime(Sendeintervall),
         log_message(ClientNumber, lists:concat(["Neuer Sendeintervall: ", trunc(Time / 1000), " Sekunden\n"])),
         getmsgid(Pid, ClientNumber, Time, 5, OwnMessages)
      end
  end.

% Schreibt die angegebene Nachricht in die Log-Datei des entsprechenden Clients.
log_message(ClientNumber, Nachricht) ->
  {ok, HostName} = inet:gethostname(),
  logging(lists:concat(["client_", ClientNumber, "@", HostName, ".log"]),lists:concat([Nachricht, "\n"]))
.

%%%%%%%%%%%%%%%%%%%%%%
%% setTimeout
% setzt Lebenzeit
%%
setTimeout(self) ->
  {ok, ConfigListe} = file:consult("client.cfg"),
  {ok, Lifetime} = werkzeug:get_config_value(lifetime, ConfigListe),
  timer:exit_after(Lifetime * 1000, self, "Ende Lebenszeit erreicht!").


%%%%%%%%%%%%%%%%%%%%%%
%% newtime
% Neuen Random Zahl für Sendeintervall
% Muss mindestens 2 Sekunden sein
%%
newtime(Sendeintervall) ->
  random:seed(now()),
  Random = random:uniform(2),
  NewTime = if Random =:= 1 ->
                trunc(Sendeintervall * 1.5);
            true ->
                trunc(Sendeintervall * 0.5)
            end,
  if NewTime < 2000 ->
      2000;
  true ->
      NewTime
  end.
